home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / lightning-0.8-tb-win.xpi / js / calMemoryCalendar.js < prev    next >
Text File  |  2008-03-18  |  17KB  |  449 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Oracle Corporation code.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  *  Oracle Corporation
  18.  * Portions created by the Initial Developer are Copyright (C) 2004
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
  23.  *   Philipp Kewisch <mozilla@kewis.ch>
  24.  *   Daniel Boelzle <daniel.boelzle@sun.com>
  25.  *
  26.  * Alternatively, the contents of this file may be used under the terms of
  27.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  28.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29.  * in which case the provisions of the GPL or the LGPL are applicable instead
  30.  * of those above. If you wish to allow use of your version of this file only
  31.  * under the terms of either the GPL or the LGPL, and not to allow others to
  32.  * use your version of this file under the terms of the MPL, indicate your
  33.  * decision by deleting the provisions above and replace them with the notice
  34.  * and other provisions required by the GPL or the LGPL. If you do not delete
  35.  * the provisions above, a recipient may use your version of this file under
  36.  * the terms of any one of the MPL, the GPL or the LGPL.
  37.  *
  38.  * ***** END LICENSE BLOCK ***** */
  39.  
  40. //
  41. // calMemoryCalendar.js
  42. //
  43.  
  44. const calCalendarManagerContractID = "@mozilla.org/calendar/manager;1";
  45. const calICalendarManager = Components.interfaces.calICalendarManager;
  46.  
  47. function calMemoryCalendar() {
  48.     this.initProviderBase();
  49.     this.initMemoryCalendar();
  50. }
  51.  
  52. calMemoryCalendar.prototype = {
  53.     __proto__: calProviderBase.prototype,
  54.  
  55.     //
  56.     // nsISupports interface
  57.     // 
  58.     QueryInterface: function (aIID) {
  59.         return doQueryInterface(this, calMemoryCalendar.prototype, aIID,
  60.                                 [Components.interfaces.calISyncCalendar,
  61.                                  Components.interfaces.calICalendarProvider]);
  62.     },
  63.  
  64.     initMemoryCalendar: function() {
  65.         this.mObservers = new calListenerBag(Components.interfaces.calIObserver);
  66.         this.mItems = { };
  67.     },
  68.  
  69.     //
  70.     // calICalendarProvider interface
  71.     //
  72.     get prefChromeOverlay() {
  73.         return null;
  74.     },
  75.  
  76.     get displayName() {
  77.         return calGetString("calendar", "memoryName");
  78.     },
  79.  
  80.     createCalendar: function mem_createCal() {
  81.         throw NS_ERROR_NOT_IMPLEMENTED;
  82.     },
  83.  
  84.     deleteCalendar: function mem_deleteCal(cal, listener) {
  85.         cal = cal.wrappedJSObject;
  86.         cal.mItems = {};
  87.  
  88.         try {
  89.             listener.onDeleteCalendar(cal, Components.results.NS_OK, null);
  90.         } catch(ex) {}
  91.     },
  92.  
  93.     mRelaxedMode: undefined,
  94.     get relaxedMode calMemoryCalendar_relaxedModeGetter() {
  95.         if (this.mRelaxedMode === undefined) {
  96.             this.mRelaxedMode = this.getProperty("relaxedMode");
  97.         }
  98.         return this.mRelaxedMode;
  99.     },
  100.  
  101.     //
  102.     // calICalendar interface
  103.     //
  104.  
  105.     getProperty: function calMemoryCalendar_getProperty(aName) {
  106.         switch (aName) {
  107.             case "cache.supported":
  108.             case "requiresNetwork":
  109.                 return false;
  110.         }
  111.         return this.__proto__.__proto__.getProperty.apply(this, arguments);
  112.     },
  113.  
  114.     // readonly attribute AUTF8String type;
  115.     get type() { return "memory"; },
  116.  
  117.     // void addItem( in calIItemBase aItem, in calIOperationListener aListener );
  118.     addItem: function (aItem, aListener) {
  119.         var newItem = aItem.clone();
  120.         return this.adoptItem(newItem, aListener);
  121.     },
  122.     
  123.     // void adoptItem( in calIItemBase aItem, in calIOperationListener aListener );
  124.     adoptItem: function (aItem, aListener) {
  125.         if (this.readOnly) 
  126.             throw Components.interfaces.calIErrors.CAL_IS_READONLY;
  127.         if (aItem.id == null && aItem.isMutable)
  128.             aItem.id = getUUID();
  129.  
  130.         if (aItem.id == null) {
  131.             if (aListener)
  132.                 aListener.onOperationComplete (this.superCalendar,
  133.                                                Components.results.NS_ERROR_FAILURE,
  134.                                                aListener.ADD,
  135.                                                aItem.id,
  136.                                                "Can't set ID on non-mutable item to addItem");
  137.             return;
  138.         }
  139.  
  140.         if (this.mItems[aItem.id] != null) {
  141.             if (this.relaxedMode) {
  142.                 // we possibly want to interact with the user before deleting
  143.                 delete this.mItems[aItem.id];
  144.             }
  145.             else {
  146.                 if (aListener) {
  147.                     aListener.onOperationComplete (this.superCalendar,
  148.                                                    Components.interfaces.calIErrors.DUPLICATE_ID,
  149.                                                    aListener.ADD,
  150.                                                    aItem.id,
  151.                                                    "ID already exists for addItem");
  152.                 }
  153.                 return;
  154.             }
  155.         }
  156.  
  157.         aItem.calendar = this.superCalendar;
  158.         var rec = aItem.recurrenceInfo;
  159.         if (rec) {
  160.             var exceptions = rec.getExceptionIds({});
  161.             for each (var exid in exceptions) {
  162.                 var exception = rec.getExceptionFor(exid, false);
  163.                 if (exception) {
  164.                     if (!exception.isMutable) {
  165.                         exception = exception.clone();
  166.                     }
  167.                     exception.calendar = this.superCalendar;
  168.                     rec.modifyException(exception);
  169.                 }
  170.             }
  171.         }
  172.         
  173.         aItem.makeImmutable();
  174.         this.mItems[aItem.id] = aItem;
  175.  
  176.         // notify the listener
  177.         if (aListener)
  178.             aListener.onOperationComplete (this.superCalendar,
  179.                                            Components.results.NS_OK,
  180.                                            aListener.ADD,
  181.                                            aItem.id,
  182.                                            aItem);
  183.         // notify observers
  184.         this.mObservers.notify("onAddItem", [aItem]);
  185.     },
  186.  
  187.     // void modifyItem( in calIItemBase aNewItem, in calIItemBase aOldItem, in calIOperationListener aListener );
  188.     modifyItem: function (aNewItem, aOldItem, aListener) {
  189.         if (this.readOnly) 
  190.             throw Components.interfaces.calIErrors.CAL_IS_READONLY;
  191.         if (!aNewItem) {
  192.             throw Components.results.NS_ERROR_INVALID_ARG;
  193.         }
  194.  
  195.         var this_ = this;
  196.         function reportError(errStr, errId) {
  197.             if (aListener) {
  198.                 aListener.onOperationComplete(this_.superCalendar,
  199.                                               errId ? errId : Components.results.NS_ERROR_FAILURE,
  200.                                               aListener.MODIFY,
  201.                                               aNewItem.id,
  202.                                               errStr);
  203.             }
  204.             return null;
  205.         }
  206.  
  207.         if (!aNewItem.id) {
  208.             // this is definitely an error
  209.             return reportError(null, "ID for modifyItem item is null");
  210.         }
  211.  
  212.         var modifiedItem = aNewItem.clone();
  213.         if (modifiedItem.parentItem != modifiedItem) {
  214.             modifiedItem.parentItem.recurrenceInfo.modifyException(modifiedItem);
  215.             modifiedItem = modifiedItem.parentItem;
  216.         }
  217.  
  218.         if (this.relaxedMode) {
  219.             if (!aOldItem) {
  220.                 aOldItem = (this.mItems[aNewItem.id] || modifiedItem);
  221.             }
  222.             aOldItem = aOldItem.parentItem;
  223.         } else {
  224.             if (!aOldItem || !this.mItems[aNewItem.id]) {
  225.                 // no old item found?  should be using addItem, then.
  226.                 return reportError("ID for modifyItem doesn't exist, is null, or is from different calendar");
  227.             }
  228.  
  229.             // do the old and new items match?
  230.             if (aOldItem.id != modifiedItem.id) {
  231.                 return reportError("item ID mismatch between old and new items");
  232.             }
  233.  
  234.             aOldItem = aOldItem.parentItem;
  235.             var storedOldItem = this.mItems[aOldItem.id];
  236.  
  237.             // compareItems is not suitable here. See bug 418805.
  238.             if (storedOldItem.icalString != aOldItem.icalString) {
  239.                 return reportError("old item mismatch in modifyItem");
  240.             }
  241.  
  242.             if (aOldItem.generation != storedOldItem.generation) {
  243.                 return reportError("generation mismatch in modifyItem");
  244.             }
  245.  
  246.             if (aOldItem.generation == modifiedItem.generation) { // has been cloned and modified
  247.                 // Only take care of incrementing the generation if relaxed mode is
  248.                 // off. Users of relaxed mode need to take care of this themselves.
  249.                 modifiedItem.generation += 1;
  250.             }
  251.         }
  252.  
  253.         modifiedItem.makeImmutable();
  254.         this.mItems[modifiedItem.id] = modifiedItem;
  255.  
  256.         if (aListener) {
  257.             aListener.onOperationComplete (this.superCalendar,
  258.                                            Components.results.NS_OK,
  259.                                            aListener.MODIFY,
  260.                                            modifiedItem.id,
  261.                                            modifiedItem);
  262.         }
  263.  
  264.         // notify observers
  265.         this.mObservers.notify("onModifyItem", [modifiedItem, aOldItem]);
  266.         return null;
  267.     },
  268.  
  269.     // void deleteItem( in calIItemBase aItem, in calIOperationListener aListener );
  270.     deleteItem: function (aItem, aListener) {
  271.         if (this.readOnly) 
  272.             throw Components.interfaces.calIErrors.CAL_IS_READONLY;
  273.         if (aItem.id == null || this.mItems[aItem.id] == null) {
  274.             if (aListener)
  275.                 aListener.onOperationComplete (this.superCalendar,
  276.                                                Components.results.NS_ERROR_FAILURE,
  277.                                                aListener.DELETE,
  278.                                                aItem.id,
  279.                                                "ID is null or is from different calendar in deleteItem");
  280.             return;
  281.         }
  282.  
  283.         var oldItem = this.mItems[aItem.id];
  284.         if (oldItem.generation != aItem.generation) {
  285.             if (aListener)
  286.                 aListener.onOperationComplete (this.superCalendar,
  287.                                                Components.results.NS_ERROR_FAILURE,
  288.                                                aListener.DELETE,
  289.                                                aItem.id,
  290.                                                "generation mismatch in deleteItem");
  291.             return;
  292.         }
  293.  
  294.         delete this.mItems[aItem.id];
  295.  
  296.         if (aListener)
  297.             aListener.onOperationComplete (this.superCalendar,
  298.                                            Components.results.NS_OK,
  299.                                            aListener.DELETE,
  300.                                            aItem.id,
  301.                                            aItem);
  302.         // notify observers
  303.         this.mObservers.notify("onDeleteItem", [oldItem]);
  304.     },
  305.  
  306.     // void getItem( in string id, in calIOperationListener aListener );
  307.     getItem: function (aId, aListener) {
  308.         if (!aListener)
  309.             return;
  310.  
  311.         if (aId == null ||
  312.             this.mItems[aId] == null) {
  313.             aListener.onOperationComplete(this.superCalendar,
  314.                                           Components.results.NS_ERROR_FAILURE,
  315.                                           aListener.GET,
  316.                                           null,
  317.                                           "IID doesn't exist for getItem");
  318.             return;
  319.         }
  320.  
  321.         var item = this.mItems[aId];
  322.         var iid = null;
  323.  
  324.         if (item instanceof Components.interfaces.calIEvent) {
  325.             iid = Components.interfaces.calIEvent;
  326.         } else if (item instanceof Components.interfaces.calITodo) {
  327.             iid = Components.interfaces.calITodo;
  328.         } else {
  329.             aListener.onOperationComplete (this.superCalendar,
  330.                                            Components.results.NS_ERROR_FAILURE,
  331.                                            aListener.GET,
  332.                                            aId,
  333.                                            "Can't deduce item type based on QI");
  334.             return;
  335.         }
  336.  
  337.         aListener.onGetResult (this.superCalendar,
  338.                                Components.results.NS_OK,
  339.                                iid,
  340.                                null, 1, [item]);
  341.  
  342.         aListener.onOperationComplete (this.superCalendar,
  343.                                        Components.results.NS_OK,
  344.                                        aListener.GET,
  345.                                        aId,
  346.                                        null);
  347.  
  348.     },
  349.  
  350.     // void getItems( in unsigned long aItemFilter, in unsigned long aCount, 
  351.     //                in calIDateTime aRangeStart, in calIDateTime aRangeEnd,
  352.     //                in calIOperationListener aListener );
  353.     getItems: function (aItemFilter, aCount,
  354.                         aRangeStart, aRangeEnd, aListener)
  355.     {
  356.         if (!aListener)
  357.             return;
  358.  
  359.         const calICalendar = Components.interfaces.calICalendar;
  360.         const calIRecurrenceInfo = Components.interfaces.calIRecurrenceInfo;
  361.  
  362.         var itemsFound = Array();
  363.  
  364.         //
  365.         // filters
  366.         //
  367.  
  368.         // item base type
  369.         var wantEvents = ((aItemFilter & calICalendar.ITEM_FILTER_TYPE_EVENT) != 0);
  370.         var wantTodos = ((aItemFilter & calICalendar.ITEM_FILTER_TYPE_TODO) != 0);
  371.         if(!wantEvents && !wantTodos) {
  372.             // bail.
  373.             aListener.onOperationComplete (this.superCalendar,
  374.                                            Components.results.NS_ERROR_FAILURE,
  375.                                            aListener.GET,
  376.                                            null,
  377.                                            "Bad aItemFilter passed to getItems");
  378.             return;
  379.         }
  380.  
  381.         // completed?
  382.         var itemCompletedFilter = ((aItemFilter & calICalendar.ITEM_FILTER_COMPLETED_YES) != 0);
  383.         var itemNotCompletedFilter = ((aItemFilter & calICalendar.ITEM_FILTER_COMPLETED_NO) != 0);
  384.         function checkCompleted(item) {
  385.             return (item.isCompleted ? itemCompletedFilter : itemNotCompletedFilter);
  386.         }
  387.  
  388.         // return occurrences?
  389.         var itemReturnOccurrences = ((aItemFilter & calICalendar.ITEM_FILTER_CLASS_OCCURRENCES) != 0);
  390.  
  391.         // figure out the return interface type
  392.         var typeIID = null;
  393.         if (itemReturnOccurrences) {
  394.             typeIID = Components.interfaces.calIItemBase;
  395.         } else {
  396.             if (wantEvents && wantTodos) {
  397.                 typeIID = Components.interfaces.calIItemBase;
  398.             } else if (wantEvents) {
  399.                 typeIID = Components.interfaces.calIEvent;
  400.             } else if (wantTodos) {
  401.                 typeIID = Components.interfaces.calITodo;
  402.             }
  403.         }
  404.  
  405.         aRangeStart = ensureDateTime(aRangeStart);
  406.         aRangeEnd = ensureDateTime(aRangeEnd);
  407.  
  408.         for (var itemIndex in this.mItems) {
  409.             var item = this.mItems[itemIndex];
  410.             var isEvent_ = isEvent(item);
  411.             if (isEvent_) {
  412.                 if (!wantEvents) {
  413.                     continue;
  414.                 }
  415.             } else if (!wantTodos) {
  416.                 continue;
  417.             }
  418.  
  419.             if (itemReturnOccurrences && item.recurrenceInfo) {
  420.                 var occurrences = item.recurrenceInfo.getOccurrences(
  421.                     aRangeStart, aRangeEnd, aCount ? aCount - itemsFound.length : 0, {});
  422.                 if (!isEvent_) {
  423.                     occurrences = occurrences.filter(checkCompleted);
  424.                 }
  425.                 itemsFound = itemsFound.concat(occurrences);
  426.             } else if ((isEvent_ || checkCompleted(item)) &&
  427.                        checkIfInRange(item, aRangeStart, aRangeEnd)) {
  428.                 itemsFound.push(item);
  429.             }
  430.             if (aCount && itemsFound.length >= aCount) {
  431.                 break;
  432.             }
  433.         }
  434.  
  435.         aListener.onGetResult (this.superCalendar,
  436.                                Components.results.NS_OK,
  437.                                typeIID,
  438.                                null,
  439.                                itemsFound.length,
  440.                                itemsFound);
  441.  
  442.         aListener.onOperationComplete (this.superCalendar,
  443.                                        Components.results.NS_OK,
  444.                                        aListener.GET,
  445.                                        null,
  446.                                        null);
  447.     }
  448. };
  449.